#!/usr/bin/env ruby
# -*- coding: binary -*-
#
# $Id$
# $Revision$
#

$stderr.puts "[!] ************************************************************************"
$stderr.puts "[!] *               The utility msfpayload is deprecated!                  *"
$stderr.puts "[!] *              It will be removed on or about 2015-06-08               *"
$stderr.puts "[!] *                   Please use msfvenom instead                        *"
$stderr.puts "[!] *  Details: https://github.com/rapid7/metasploit-framework/pull/4333   *"
$stderr.puts "[!] ************************************************************************"

msfbase = __FILE__
while File.symlink?(msfbase)
  msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
end

$:.unshift(File.expand_path(File.join(File.dirname(msfbase), 'lib')))
require 'msfenv'



$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']

require 'rex'

$args = Rex::Parser::Arguments.new(
  "-h" => [ false, "Help banner"                                                       ],
  "-l" => [ false, "List available payloads"                                           ]
)

#
# Nuff said.
#
def usage
  $stderr.puts("\n" +
    "    Usage: #{$0} [<options>] <payload> [var=val] <[S]ummary|C|Cs[H]arp|" +
    "[P]erl|Rub[Y]|[R]aw|[J]s|e[X]e|[D]ll|[V]BA|[W]ar|Pytho[N]|s[O]>\n" +
    $args.usage)
  exit
end

cmd = nil
rest = []

# Parse the argument and rock it
$args.parse(ARGV) { |opt, idx, val|
  #puts "opt[%d]: #{opt.inspect} / #{val.inspect}" % idx

  case opt
  when "-l"
    cmd = "list"
    break

  # Non-option (don't begin with '-') are processed here
  when nil
    rest << val

  end
}

usage if cmd != "list" && rest.length < 2

require 'msf/ui'
require 'msf/base'

#
# Dump the list of payloads
#
def dump_payloads
  tbl = Rex::Ui::Text::Table.new(
    'Indent'  => 4,
    'Header'  => "Framework Payloads (#{$framework.stats.num_payloads} total)",
    'Columns' =>
      [
        "Name",
        "Description"
      ])

  $framework.payloads.each_module { |name, mod|
    tbl << [ name, mod.new.description ]
  }

  "\n" + tbl.to_s + "\n"
end

# Initialize the simplified framework instance.
$framework = Msf::Simple::Framework.create(
  :module_types => [ Msf::MODULE_PAYLOAD, Msf::MODULE_NOP ],
  'DisableDatabase' => true
)

if cmd == "list"
  puts dump_payloads
  exit
end


# Get the payload name we'll be using
payload_name = rest.shift

# Process special var/val pairs...
Msf::Ui::Common.process_cli_arguments($framework, rest)

# Create the payload instance
payload = $framework.payloads.create(payload_name)

if (payload == nil)
  $stderr.puts "Invalid payload: #{payload_name}"
  exit
end

# Evalulate the command
cmd = rest.pop.downcase

# Populate the framework datastore
options = {}
rest.each do |x|
  k,v = x.split("=", 2)
  options[k.upcase] = v.to_s
end

# if LHOST is not set auto set it
if payload_name =~ /[\_\/]reverse/ and options['LHOST'].nil?
  options['LHOST'] = Rex::Socket.source_address
end


payload.datastore.merge! options

if cmd =~ /^(p|y|r|d|c|h|j|x|b|v|w|n|o)$/
  fmt = 'perl' if cmd =~ /^p$/
  fmt = 'ruby' if cmd =~ /^y$/
  fmt = 'raw' if cmd =~ /^(r|x|d|o)$/
  fmt = 'raw' if cmd =~ /^v$/
  fmt = 'c' if cmd =~ /^c$/
  fmt = 'csharp' if cmd =~ /^h$/
  fmt = 'js_be' if cmd =~ /^j$/ && Rex::Arch.endian(payload.arch) == ENDIAN_BIG
  fmt = 'js_le' if cmd =~ /^j$/ && !fmt
  fmt = 'java'  if cmd =~ /^b$/
  fmt = 'raw' if cmd =~ /^w$/
  fmt = 'python' if cmd =~ /^n$/
  enc = options['ENCODER']

  begin
    buf = payload.generate_simple(
        'Format'    => fmt,
        'Options'   => options)
  rescue
    $stderr.puts "Error generating payload: #{$!}"
    exit
  end

  $stdout.binmode

  if cmd =~ /^x$/
    note =
      "Created by msfpayload (http://www.metasploit.com).\n" +
      "Payload: " + payload.refname + "\n" +
      " Length: " + buf.length.to_s + "\n" +
      "Options: " + options.inspect + "\n"

    arch = payload.arch
    plat = payload.platform.platforms

    exe  = Msf::Util::EXE.to_executable($framework, arch, plat, buf)

    if !exe && plat.index(Msf::Module::Platform::Java)
      exe = payload.generate_jar.pack
    end

    if exe
      $stderr.puts(note)
      $stdout.write(exe)
      exit(0)
    end

    $stderr.puts "No executable format support for this arch/platform"
    exit(-1)
  end

  if cmd =~ /^v$/
    exe = Msf::Util::EXE.to_win32pe($framework, buf)
    note =
      "'Created by msfpayload (http://www.metasploit.com).\r\n" +
      "'Payload: " + payload.refname + "\r\n" +
      "' Length: " + buf.length.to_s + "\r\n" +
      "'Options: " + options.inspect + "\r\n"

    vba = note + "\r\n" + Msf::Util::EXE.to_exe_vba(exe)
    $stdout.write(vba)
    exit(0)
  end

  if cmd =~ /^d$/
    dll = Msf::Util::EXE.to_win32pe_dll($framework, buf)
    note =
      "Created by msfpayload (http://www.metasploit.com).\r\n" +
      "Payload: " + payload.refname + "\r\n" +
      " Length: " + buf.length.to_s + "\r\n" +
      "Options: " + options.inspect + "\r\n"

    if dll
      $stderr.puts(note)
      $stdout.write(dll)
      exit(0)
    end

    $stderr.puts "Failed to build dll"
    exit(-1)
  end

  if cmd =~ /^o$/
    so = Msf::Util::EXE.to_linux_x64_elf_dll($framework, buf)
    note =
       "Created by msfpayload (http://www.metasploit.com).\r\n" +
       "Payload: " + payload.refname + "\r\n" +
       " Length: " + buf.length.to_s + "\r\n" +
       "Options: " + options.inspect + "\r\n"

    if so
      $stderr.puts(note)
      $stdout.write(so)
      exit(0)
    end

    $stderr.puts "Failed to build dll"
    exit(-1)
  end

  if cmd =~ /^w$/
    note =
      "Created by msfpayload (http://www.metasploit.com).\n" +
      "Payload: " + payload.refname + "\n" +
      " Length: " + buf.length.to_s + "\n" +
      "Options: " + options.inspect + "\n"

    arch = payload.arch
    plat = payload.platform.platforms

    exe  = Msf::Util::EXE.to_executable($framework, arch, plat, buf)
    if (!exe && payload.respond_to?(:generate_war))
      exe = payload.generate_war.pack
    elsif exe
      exe  = Msf::Util::EXE.to_jsp_war(exe)
    end

    if exe
      $stderr.puts(note)
      $stdout.write(exe)
      exit(0)
    end

    $stderr.puts "No executable format support for this arch/platform"
    exit(-1)
  end

  $stdout.write(buf)

elsif cmd =~ /^(s|o)$/
  payload.datastore.import_options_from_s(rest.join('_|_'), '_|_')
  puts Msf::Serializer::ReadableText.dump_module(payload)

else
  $stderr.puts "Invalid command: #{cmd.inspect}"

end
